﻿using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using CliWrap.Builders;
using CommunityToolkit.Mvvm.Input;
using MahApps.Metro.Controls.Dialogs;
using N_m3u8DL_RE.Common.Util;
using N_m3u8DL_RE.Enums;
using Newtonsoft.Json;
using Notifications.Wpf;
using VideoTools.Extension;
using VideoTools.Services;
using VideoTools.Tasks;
using VideoTools.Util;
using VideoTools.vo;
using ComboBox = System.Windows.Controls.ComboBox;
using TextBox = System.Windows.Controls.TextBox;

namespace VideoTools.Commands
{
    public class DownloadM3u8Commands : NotifyPropertyBase
    {
        private static readonly string m3u8ConfigFile = "m3u8.json";
        private Dictionary<string, M3u8> m3u8Dict = new Dictionary<string, M3u8>();

        private static volatile DownloadM3u8Commands _instance;
        private static readonly object SyncRoot = new object();
        public static DownloadM3u8Commands Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (SyncRoot)
                    {
                        if (_instance == null)
                        {
                            _instance = new DownloadM3u8Commands();
                        }
                    }
                }

                return _instance;
            }
        }

        public DownloadM3u8TaskQueueManager TaskManager { get; } =
            DownloadM3u8TaskQueueManager.Instance;

        public DownloadM3u8Commands()
        {
            string content = File.ReadAllText(m3u8ConfigFile);
            List<M3u8> m3u8List = JsonConvert.DeserializeObject<List<M3u8>>(content);
            foreach (M3u8 c in m3u8List)
            {
                M3u8ConfigList.Add(c);
                m3u8Dict.Add(c.domain, c);
            }
            _StartIndexs.Add(0);
            _StartIndexs.Add(1);
            _MaxSizes.Add(0);
            _MaxSizes.Add(800);
            _MaxSizes.Add(1280);
            _MaxSizes.Add(1920);
            TaskManager.MaxConcurrentTasks = AppConfig.Instance.MaxConcurrentDownloadCount;
            foreach (EncryptMethod em in Utils.GetAllEnumValues<EncryptMethod>())
            {
                EncryptMethods.Add(em);
            }
        }


        private ObservableCollection<int> _MaxSizes = new ObservableCollection<int>();

        public ObservableCollection<int> MaxSizes
        {
            get => _MaxSizes;
        }
        private ObservableCollection<M3u8> _M3u8ConfigList = new ObservableCollection<M3u8>();

        public ObservableCollection<M3u8> M3u8ConfigList
        {
            get => _M3u8ConfigList;
            set { SetProperty(ref _M3u8ConfigList, value); }
        }

        private ObservableCollection<int> _StartIndexs = new ObservableCollection<int>();

        public ObservableCollection<int> StartIndexs
        {
            get => _StartIndexs;
        }
        private M3u8 _SelectedConfig = null;
        public M3u8 SelectedConfig
        {
            get => _SelectedConfig;
            set
            {
                SetProperty(ref _SelectedConfig, value);
                DeleteWebsitEnabled = value != null;
            }
        }
        private bool _DeleteWebsitEnabled = false;
        public bool DeleteWebsitEnabled
        {
            get => _DeleteWebsitEnabled;
            set { SetProperty(ref _DeleteWebsitEnabled, value); }
        }
        private string _TaskMessage = "";
        public string TaskMessage
        {
            get => _TaskMessage;
            set { SetProperty(ref _TaskMessage, value); }
        }
        private ObservableCollection<EncryptMethod> _EncryptMethods =
            new ObservableCollection<EncryptMethod>();
        public ObservableCollection<EncryptMethod> EncryptMethods
        {
            get => _EncryptMethods;
            set => SetProperty(ref _EncryptMethods, value);
        }
        private EncryptMethod _EncryptMethod;

        public EncryptMethod EncryptMethod
        {
            get => _EncryptMethod;
            set => SetProperty(ref _EncryptMethod, value);
        }
        private static Random random = new Random();

        private ICommand _SupportWebsiteCommand;
        private ICommand _OpenSupportWebsiteCommand;
        private ICommand _StopAllCommand;
        private ICommand _StartAllCommand;
        private ICommand _RemoveFailedCommand;
        private ICommand _StopSelectedCommand;
        private ICommand _StartSelectedCommand;
        private ICommand _RemoveSelectedCommand;
        private ICommand _OrderByNameDownloadsCommand;
        private ICommand _OrderByRateDownloadsCommand;
        private ICommand _ClearBatchFileCommand;
        private ICommand _CopyTaskLogCommand;
        private ICommand _CopyTaskUrlCommand;
        private ICommand _CopyTaskNameCommand;
        private ICommand _OpenBatchFileCommand;
        private ICommand _AddNewWebsitCommand;
        private ICommand _DeleteWebsitCommand;
        private ICommand _AddNewTaskCommand;
        private ICommand _addTaskCommand;
        private ICommand _ClearCompletedTasksCommand;
        private ICommand _ActionTaskItemCommand;
        private ICommand _OpenSettingCommand;
        private ICommand _OpenDeleteWindowCommand;
        private ICommand _EncryptMethodChangedCommand;

        public ICommand OpenSupportWebsiteCommand =>
            _OpenSupportWebsiteCommand
            ?? (
                _OpenSupportWebsiteCommand = new RelayCommand<object>(o =>
                {
                    if (o is string urlx)
                    {
                        string url = "https://" + urlx;
                        Util.Utils.OpenUrlUsingEdge(url);
                    }
                })
            );
        public ICommand EncryptMethodChangedCommand =>
            _EncryptMethodChangedCommand
            ?? (
                _EncryptMethodChangedCommand = new RelayCommand<object>(o =>
                {
                    if (o == null)
                        return;
                    EncryptMethod = (EncryptMethod)o;
                })
            );
        public ICommand AddTaskCommand => _addTaskCommand ??= new RelayCommand(AddTask);

        public ICommand ActionTaskItemCommand =>
            _ActionTaskItemCommand ??= new RelayCommand<DownloadM3u8TaskItem>(ActionTaskItem);

        public ICommand ClearCompletedTasksCommand =>
            _ClearCompletedTasksCommand ??= new RelayCommand(() =>
            {
                TaskManager.ClearCompletedTasks();
            });

        private void AddTask()
        {
            int taskNumber = TaskManager.Tasks.Count + 1;
            for (int i = 0; i < 10; i++)
            {
                var taskItem = new DownloadM3u8TaskItem
                {
                    VideoName = $"任务 {taskNumber} - {i + 1}",
                    Status = vo.TaskStatus.Pending,
                    Method = EncryptMethod.NONE,
                    RequestUrl = new Uri(
                        "http://www.abc.com/" + DownloadM3u8Commands.GenerateRandomString(20)
                    ),
                };

                TaskManager.AddTask(taskItem, TaskAction);
            }
        }

        private Action<CancellationToken, IProgress<int>, DownloadM3u8TaskItem> TaskAction = async (
            token,
            progress,
            item
        ) =>
        {
            //item.Info(AppConstants.DoubleClickMessage);
            //string[] infos = item.VideoName.Split("/");
            //DownloadArgument argument = new DownloadArgument()
            //{
            //    Input = item.RequestUrl.ToString(),
            //    ThreadCount = AppConfig.Instance.MaxThreadCount,
            //    DelAfterDone = AppConfig.Instance.IsCleanUp,
            //    CheckSegmentsCount = !AppConfig.Instance.ForcedMerger,
            //    DownloadRetryCount = AppConfig.Instance.RetryCount,
            //    HttpRequestTimeout = AppConfig.Instance.Timeouts,
            //    SaveDir =
            //        AppConfig.Instance.SavePath + (infos.Length > 1 ? "\\" + infos[0] : ""),
            //    SaveName = (infos.Length > 1 ? infos[1] : infos[0]),
            //    TmpDir =
            //        AppConfig.Instance.SavePath
            //        + "\\"
            //        + infos[0]
            //        + (infos.Length > 1 ? "\\" + infos[1] : ""),
            //    NoDateInfo = true,
            //    AllowHlsMultiExtMap = false,
            //    AutoSelect = false,
            //    SubOnly = false,
            //    BinaryMerge = false,
            //    UseFFmpegConcatDemuxer = false,
            //    AutoSubtitleFix = true,
            //    WriteMetaJson = true,
            //    AppendUrlParams = false,
            //    MP4RealTimeDecryption = false,
            //    MuxAfterDone = false,
            //    SubtitleFormat = SubtitleFormat.SRT,
            //};
            //string header = AppConfig.Instance.Headers;
            //if (header != null && header.Length > 0)
            //{
            //    string[] headers = header.Split("\r\n");
            //    Dictionary<string, string> headerDict = new Dictionary<string, string>();
            //    foreach (var h in headers)
            //    {
            //        string[] hs = h.Split(":");
            //        headerDict[hs[0]] = hs[1];
            //    }
            //}
            //if (!string.IsNullOrEmpty(item.Key) && !string.IsNullOrEmpty(item.Iv))
            //{
            //    argument.CustomHLSMethod = item.Method;
            //    argument.CustomHLSKey = KeyOrIvToBytes(item.Key);
            //    argument.CustomHLSIv = KeyOrIvToBytes(item.Iv);
            //}
            //try
            //{
            //    await new M3u8Download(argument, item).DownloadAsync(argument, item);
            //    new SoundService().PlaySuccess();
            //}
            //catch(Exception ex)
            //{
            //    item.Error("下载异常：" + ex.Message);
            //    item.Status = vo.TaskStatus.Failed;
            //    new SoundService().PlayError();
            //}
            //DownloadM3u8TaskQueueManager.Instance._runningTasks.TryRemove(item, out _);


            //for (int i = 0; i <= 100; i++)
            //{
            //    if (!item.ExitTask)
            //    {
            //        progress.Report(i);
            //        item.FrameSize = "1920*1080";
            //        item.Segment = i + "/100";
            //        item.DownloadBytes = (i * 10) + "M/1000M";
            //        item.Speed = random.Next(10) + "M/s";
            //        if (i % 10 == 0)
            //        {
            //            item.Error("整除10，异常" + i);
            //        }
            //        else
            //        {
            //            if (i % 5 == 0)
            //            {
            //                item.Warn("整除5，警告" + i);
            //            }
            //            else
            //            {
            //                item.Info("整除5，信息" + i);
            //            }
            //        }
            //        System.Threading.Thread.Sleep(random.Next(300));
            //    }
            //}

            try
            {
                Process process = new Process();
                token.Register(() =>
                {
                    if (!process.HasExited)
                    {
                        try
                        {
                            item.Killed = true;
                            process.Kill();
                            Thread.Sleep(500);
                        }
                        catch { }
                    }
                });
                process.StartInfo.FileName = "M3u8Download ";
                process.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
                item.Command = getParam(item);
                string param = item.Command;
                item.Info("参数 M3u8Download " + param);
                process.StartInfo.Arguments = param;
                process.StartInfo.CreateNoWindow = true; //显示命令行窗口
                process.StartInfo.UseShellExecute = false;
                IDictionary<string, string?> environment = process.StartInfo.Environment;
                environment["taskItem_Path"] = item.RequestUrl.ToString();
                //将输出信息重定向
                process.StartInfo.RedirectStandardInput = true;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError = true;
                process.EnableRaisingEvents = true;
                process.Exited += new EventHandler(download_Exited);
                process.OutputDataReceived += new DataReceivedEventHandler(
                    download_OutputDataReceived
                );
                process.ErrorDataReceived += new DataReceivedEventHandler(
                    download_ErrorDataReceived
                );
                process.Start();
                //开始异步读取输出
                process.BeginOutputReadLine();
                process.BeginErrorReadLine();
                process.WaitForExit();
            }
            catch (Exception ex)
            {
                item.Status = vo.TaskStatus.Failed;
                item.Speed = "异常退出";
                item.Error("下载异常：" + ex.Message);
            }
            finally { }
        };

        public static string getParam(DownloadM3u8TaskItem item)
        {
            string[] infos = item.VideoName.Split("/");
            var args = new ArgumentsBuilder();
            args.Add("--input")
                .Add(item.RequestUrl.ToString())
                .Add("--thread-count")
                .Add(AppConfig.Instance.MaxThreadCount)
                .Add("--del-after-done")
                .Add(AppConfig.Instance.IsCleanUp.ToString())
                .Add("--check-segments-count")
                .Add((!AppConfig.Instance.ForcedMerger).ToString())
                .Add("--download-retry-count")
                .Add(AppConfig.Instance.RetryCount)
                .Add("--http-request-timeout")
                .Add(AppConfig.Instance.Timeouts)
                .Add("--save-dir")
                .Add(AppConfig.Instance.SavePath + (infos.Length > 1 ? "\\" + infos[0] : ""))
                .Add("--save-name")
                .Add((infos.Length > 1 ? infos[1] : infos[0]))
                .Add("--tmp-dir")
                .Add(
                    AppConfig.Instance.SavePath
                        + "\\"
                        + infos[0]
                        + (infos.Length > 1 ? "\\" + infos[1] : "")
                );
            string header = AppConfig.Instance.Headers;
            if (header != null && header.Length > 0)
            {
                string[] headers = header.Split("\r\n");
                foreach (var h in headers)
                {
                    string[] hs = h.Split(":");
                    args.Add("--header").Add(string.Format("{0}:{1}", hs[0], hs[1]));
                }
            }
            if (!string.IsNullOrEmpty(item.Key) && !string.IsNullOrEmpty(item.Iv))
            {
                args.Add("--custom-hls-method")
                    .Add(item.Method)
                    .Add("--custom-hls-key")
                    .Add(item.Key)
                    .Add("--custom-hls-iv")
                    .Add(item.Iv);
            }

            return args.Build();
        }

        static void download_OutputDataReceived(Object sender, DataReceivedEventArgs e)
        {
            string? data = e.Data;
            Process process = (Process)sender;
            string path = process.StartInfo.Environment["taskItem_Path"];
            DownloadM3u8TaskItem taskItem =
                DownloadM3u8TaskQueueManager.Instance.Tasks.FirstOrDefault(t =>
                    t.RequestUrl.ToString().Equals(path)
                );
            if (taskItem == null)
            {
                return;
            }

            if (data != null && data.Length > 0)
            {
                if (data.Contains("Done"))
                {
                    taskItem.Status = vo.TaskStatus.Completed;
                    taskItem.Speed = "";
                    var contentb = new NotificationContent()
                    {
                        Title = "下载完成",
                        Type = NotificationType.Information,
                    };
                    //AppManager.Instance.NotificationManager.Show(contentb);
                    new SoundService().PlaySuccess();
                }
                else if (data.Contains("percent"))
                {
                    //percent 271/706 38.39% 189.33MB/504.40MB 25.66MB/s
                    data = data.Trim();
                    string[] infos = data.Split(" ");
                    string p = infos[2].Replace("%", "");
                    double percent = double.Parse(p);
                    percent = percent / (double)100;
                    taskItem.Progress1 = percent;
                    taskItem.FrameSize = infos[5];
                    taskItem.Segment = infos[1];
                    taskItem.DownloadBytes = infos[3];
                    taskItem.Speed = infos[4];
                }
                else if (data.ToLower().Contains("exception"))
                {
                    taskItem.Status = vo.TaskStatus.Failed;
                    taskItem.Info(data);
                    taskItem.Cancel();
                }
                else
                {
                    if (data.Trim().Length > 0)
                    {
                        taskItem.Info(data);
                    }
                }
            }
        }

        static void download_ErrorDataReceived(Object sender, DataReceivedEventArgs e)
        {
            string info = e.Data;
            if (info == null)
            {
                return;
            }
            Process process = (Process)sender;
            string path = process.StartInfo.Environment["taskItem_Path"];
            DownloadM3u8TaskItem taskItem =
                DownloadM3u8TaskQueueManager.Instance.Tasks.FirstOrDefault(t =>
                    t.RequestUrl.ToString().Equals(path)
                );
            if (taskItem == null)
            {
                return;
            }
            if (info.ToLower().Contains("exception"))
            {
                taskItem.Status = vo.TaskStatus.Failed;
                taskItem.Error(info);
            }
        }

        static void download_Exited(Object sender, EventArgs e)
        {
            Process process = (Process)sender;
            string path = process.StartInfo.Environment["taskItem_Path"];
            DownloadM3u8TaskItem taskItem =
                DownloadM3u8TaskQueueManager.Instance.Tasks.FirstOrDefault(t =>
                    t.RequestUrl.ToString().Equals(path)
                );
            if (taskItem == null)
            {
                return;
            }
            taskItem.Info("任务退出" + path);
        }

        public static string GenerateRandomString(int length)
        {
            var random = new Random();
            return new string(
                Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray()
            );
        }

        public const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

        private void ActionTaskItem(DownloadM3u8TaskItem task)
        {
            if (task.Status == vo.TaskStatus.Pending)
            {
                task.Cancel();
            }
            else if (task.Status == vo.TaskStatus.Running)
            {
                task.Cancel();
            }
            else if (task.Status == vo.TaskStatus.Failed)
            {
                TaskManager.ContinueTask(task);
            }
            else if (task.Status == vo.TaskStatus.Completed)
            {
                string v = Path.Combine(AppConfig.Instance.SavePath, task.VideoName) + ".mp4";
                v = v.Replace("/", "\\");
                Process.Start(AppConfig.Instance.VideoPlayerPath, v);
            }
        }

        public ICommand OpenSettingCommand =>
            _OpenSettingCommand
            ?? (
                _OpenSettingCommand = new RelayCommand<object>(o =>
                {
                    MainWindowCommands.Instance.dialog = new CustomDialog(
                        MainWindow.Instance.MetroDialogOptions
                    )
                    {
                        Content = VideoView.DownloadM3u8SettingWindow.Instance,
                        Title = "下载设置",
                        Style = (Style)
                            System.Windows.Application.Current.Resources["CustomDialogStyle"], // 应用样式
                    };
                    MainWindow.Instance.ShowMetroDialogAsync(MainWindowCommands.Instance.dialog);
                })
            );
        public ICommand OpenDeleteWindowCommand =>
            _OpenDeleteWindowCommand
            ?? (
                _OpenDeleteWindowCommand = new RelayCommand<object>(o =>
                {
                    if (DownloadM3u8TaskQueueManager.Instance.SelectedTasks.Count > 0)
                    {
                        MainWindowCommands.Instance.dialog = new CustomDialog(
                            MainWindow.Instance.MetroDialogOptions
                        )
                        {
                            Content = VideoView.DownloadM3u8DeleteWindow.Instance,
                            Title = "注意",
                            Style = (Style)
                                System.Windows.Application.Current.Resources["CustomDialogStyle"], // 应用样式
                        };
                        MainWindow.Instance.ShowMetroDialogAsync(
                            MainWindowCommands.Instance.dialog
                        );
                    }
                })
            );

        public ICommand SupportWebsiteCommand =>
            _SupportWebsiteCommand
            ?? (
                _SupportWebsiteCommand = new RelayCommand<object>(o =>
                {
                    if (o is System.Windows.Controls.Button button)
                    {
                        if (button.ContextMenu != null)
                        {
                            button.ContextMenu.PlacementTarget = button;
                            button.ContextMenu.Placement = PlacementMode.Bottom;
                            button.ContextMenu.IsOpen = true;
                        }
                    }
                    else if (o is Popup popup)
                    {
                        popup.IsOpen = true;
                    }
                })
            );

        public ICommand StopAllCommand =>
            _StopAllCommand
            ?? (
                _StopAllCommand = new RelayCommand<object>(o =>
                {
                    TaskManager.StopAllTasks();
                })
            );
        public ICommand StartAllCommand =>
            _StartAllCommand
            ?? (
                _StartAllCommand = new RelayCommand<object>(o =>
                {
                    TaskManager.StartAllTask();
                })
            );

        public ICommand RemoveFailedCommand =>
            _RemoveFailedCommand
            ?? (
                _RemoveFailedCommand = new RelayCommand<object>(o =>
                {
                    TaskManager.ClearFailedTasks();
                })
            );
        public ICommand StopSelectedCommand =>
            _StopSelectedCommand
            ?? (
                _StopSelectedCommand = new RelayCommand<object>(o =>
                {
                    TaskManager.StopSelected();
                })
            );
        public ICommand StartSelectedCommand =>
            _StartSelectedCommand
            ?? (
                _StartSelectedCommand = new RelayCommand<object>(o =>
                {
                    foreach (var item in TaskManager.SelectedTasks)
                    {
                        TaskManager.ContinueTask(item);
                    }
                })
            );
        public ICommand RemoveSelectedCommand =>
            _RemoveSelectedCommand
            ?? (
                _RemoveSelectedCommand = new RelayCommand<object>(o =>
                {
                    bool deleteCache = (bool)o;
                    TaskManager.DeleteSelected(deleteCache);
                    if (MainWindowCommands.Instance.dialog != null)
                    {
                        MainWindow.Instance.HideMetroDialogAsync(
                            MainWindowCommands.Instance.dialog
                        );
                        MainWindowCommands.Instance.dialog = null;
                    }
                })
            );

        public ICommand OrderByNameDownloadsCommand =>
            _OrderByNameDownloadsCommand
            ?? (
                _OrderByNameDownloadsCommand = new RelayCommand<object>(o =>
                {
                    TaskManager.OrderByNameTasks();
                })
            );
        public ICommand OrderByRateDownloadsCommand =>
            _OrderByRateDownloadsCommand
            ?? (
                _OrderByRateDownloadsCommand = new RelayCommand<object>(o =>
                {
                    TaskManager.OrderByRateTasks();
                })
            );
        public ICommand ClearBatchFileCommand =>
            _ClearBatchFileCommand
            ?? (
                _ClearBatchFileCommand = new RelayCommand<object>(o =>
                {
                    TaskManager.ClearAllTask();
                    File.Delete(AppConstants.DownloadM3u8_Batch_File);
                })
            );

        public ICommand CopyTaskLogCommand =>
            _CopyTaskLogCommand
            ?? (
                _CopyTaskLogCommand = new RelayCommand<object>(o =>
                {
                    if (o == null)
                        return;
                    DownloadM3u8TaskItem model = (DownloadM3u8TaskItem)o;
                    Utils.CopyToClipboard(model.CopyLog(), "日志");
                })
            );

        public ICommand CopyTaskUrlCommand =>
            _CopyTaskUrlCommand
            ?? (
                _CopyTaskUrlCommand = new RelayCommand<object>(o =>
                {
                    DownloadM3u8TaskItem model = (DownloadM3u8TaskItem)o;
                    Utils.CopyToClipboard(model.RequestUrl.ToString(), "地址");
                })
            );

        public ICommand CopyTaskNameCommand =>
            _CopyTaskNameCommand
            ?? (
                _CopyTaskNameCommand = new RelayCommand<object>(o =>
                {
                    DownloadM3u8TaskItem model = (DownloadM3u8TaskItem)o;
                    Utils.CopyToClipboard(model.VideoName, "名称");
                })
            );

        public ICommand OpenBatchFileCommand =>
            _OpenBatchFileCommand
            ?? (
                _OpenBatchFileCommand = new RelayCommand<object>(o =>
                {
                    if (!File.Exists(AppConstants.DownloadM3u8_Batch_File))
                    {
                        return;
                    }
                    TaskMessage = AppConstants.DownloadM3u8_Task_Message;
                    string[] lines = File.ReadAllLines(AppConstants.DownloadM3u8_Batch_File);
                    foreach (var line in lines)
                    {
                        if (line.Length > 10)
                        {
                            DownloadM3u8TaskItem taskItem =
                                JsonConvert.DeserializeObject<DownloadM3u8TaskItem>(line);
                            string tmpVideoName = Utils.GenerateFileNameWithoutExtension(
                                taskItem.VideoName
                            );
                            string fileFullPath = System.IO.Path.Combine(
                                AppConfig.Instance.SavePath,
                                tmpVideoName
                            );
                            if (!Utils.EnsureFileNotExist(fileFullPath))
                            {
                                taskItem.Status = vo.TaskStatus.Pending;
                                TaskManager.AddTask(taskItem, TaskAction);
                                taskItem.Info("已从批文件添加 " + taskItem.VideoName);
                            }
                        }
                    }
                    TaskMessage = "";
                })
            );

        public ICommand DeleteWebsitCommand =>
            _DeleteWebsitCommand
            ?? (
                _DeleteWebsitCommand = new RelayCommand<object>(o =>
                {
                    M3u8 cfg = SelectedConfig;
                    if (cfg == null)
                        return;
                    M3u8ConfigList.Remove(cfg);
                    var controlArray = (object[])o;

                    TextBox tbxDomain = (TextBox)controlArray[0];
                    TextBox tbxTitleReg = (TextBox)controlArray[1];
                    TextBox tbxUrlReg = (TextBox)controlArray[2];
                    TextBox tbxM3u8Reg = (TextBox)controlArray[3];
                    ComboBox cbxStartIndex = (ComboBox)controlArray[4];
                    tbxDomain.Text = "";
                    tbxTitleReg.Text = "";
                    tbxUrlReg.Text = "";
                    tbxM3u8Reg.Text = "";
                    cbxStartIndex.SelectedIndex = -1;
                })
            );
        public ICommand AddNewWebsitCommand =>
            _AddNewWebsitCommand
            ?? (
                _AddNewWebsitCommand = new RelayCommand<object>(o =>
                {
                    var controlArray = (object[])o;

                    TextBox tbxDomain = (TextBox)controlArray[0];
                    TextBox tbxTitleReg = (TextBox)controlArray[1];
                    TextBox tbxUrlReg = (TextBox)controlArray[2];
                    TextBox tbxM3u8Reg = (TextBox)controlArray[3];
                    ComboBox cbxStartIndex = (ComboBox)controlArray[4];
                    if (
                        string.IsNullOrEmpty(tbxDomain.Text)
                        || string.IsNullOrEmpty(tbxTitleReg.Text)
                        || string.IsNullOrEmpty(tbxUrlReg.Text)
                        || string.IsNullOrEmpty(tbxM3u8Reg.Text)
                        || cbxStartIndex.SelectedIndex < 0
                    )
                    {
                        var content = new NotificationContent()
                        {
                            Title = "配置规则",
                            Message = "请填写相关信息",
                            Type = NotificationType.Warning,
                        };
                        AppManager.Instance.NotificationManager.Show(content);
                        return;
                    }
                    M3u8 cfg = null;
                    foreach (var ele in M3u8ConfigList)
                    {
                        if (ele.domain.Equals(tbxDomain.Text))
                        {
                            //修改
                            ele.titleReg = tbxTitleReg.Text;
                            ele.urlReg = tbxUrlReg.Text;
                            ele.m3u8UrlReg = tbxM3u8Reg.Text;
                            ele.start = cbxStartIndex.SelectedIndex;
                            cfg = ele;
                        }
                    }
                    if (cfg == null)
                    {
                        cfg = new M3u8();
                        cfg.domain = tbxDomain.Text;
                        cfg.titleReg = tbxTitleReg.Text;
                        cfg.urlReg = tbxUrlReg.Text;
                        cfg.m3u8UrlReg = tbxM3u8Reg.Text;
                        cfg.start = cbxStartIndex.SelectedIndex;
                        M3u8ConfigList.Add(cfg);
                    }
                })
            );

        public ICommand AddNewTaskCommand =>
            _AddNewTaskCommand
            ?? (
                _AddNewTaskCommand = new RelayCommand<object>(o =>
                {
                    var controlArray = (object[])o;

                    TextBox tbxLastPlayerUrl = (TextBox)controlArray[0];
                    TextBox tbxVideoName = (TextBox)controlArray[1];
                    ComboBox cbxMethod = (ComboBox)controlArray[2];
                    int index = cbxMethod.SelectedIndex;
                    EncryptMethod method = (EncryptMethod)cbxMethod.SelectedIndex;
                    TextBox tbxKey = (TextBox)controlArray[3];
                    TextBox tbxIV = (TextBox)controlArray[4];
#if DEBUG
                    string p = tbxLastPlayerUrl.Text;
                    string[] xs = p.Split("\\");
                    string[] strings = Directory.GetFiles(p);
                    foreach (var s in strings)
                    {
                        string cnt = File.ReadAllText(s);
                        string[] infos = cnt.Split("https");
                        if (infos.Length < 2)
                        {
                            int ad = 1;
                            continue;
                        }
                        DownloadM3u8TaskItem item = new DownloadM3u8TaskItem()
                        {
                            RequestUrl = new Uri("https" + infos[1]),
                            VideoName = xs[xs.Length - 1] + "/" + infos[0],
                            Method = EncryptMethod.NONE,
                            Key = "",
                            Iv = "",
                        };
                        var settings = new JsonSerializerSettings
                        {
                            ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                        };
                        string v = JsonConvert.SerializeObject(item, Formatting.None, settings);
                        File.AppendAllLines(
                            AppConstants.DownloadM3u8_Batch_File,
                            new string[] { v }
                        );
                    }
                    return;
#endif
                    if (string.IsNullOrEmpty(tbxLastPlayerUrl.Text))
                    {
                        var content = new NotificationContent()
                        {
                            Title = "添加任务",
                            Message = "请填写待下载url",
                            Type = NotificationType.Error,
                        };
                        AppManager.Instance.NotificationManager.Show(content);
                        return;
                    }
                    TaskMessage = AppConstants.DownloadM3u8_Task_Message;
                    List<DownloadM3u8TaskItem> tasks = GetTaskItem(
                        tbxLastPlayerUrl.Text,
                        tbxVideoName.Text,
                        method,
                        tbxKey.Text,
                        tbxIV.Text
                    );

                    if (tasks == null || tasks.Count == 0)
                    {
                        tbxLastPlayerUrl.Text = "";
                        tbxVideoName.Text = "";
                        tbxKey.Text = "";
                        tbxIV.Text = "";
                        return;
                    }
                    foreach (var item in tasks)
                    {
                        string tmpVideoName = Utils.GenerateFileNameWithoutExtension(
                            item.VideoName
                        );
                        string fileFullPath = System.IO.Path.Combine(
                            AppConfig.Instance.SavePath,
                            tmpVideoName
                        );
                        if (!Utils.EnsureFileNotExist(fileFullPath))
                        {
                            TaskManager.AddTask(item, TaskAction);
                            item.Info("已添加 " + item.VideoName);
                        }
                    }
                    tbxLastPlayerUrl.Text = "";
                    tbxVideoName.Text = "";
                    tbxKey.Text = "";
                    tbxIV.Text = "";
                    TaskMessage = "";
                })
            );

        static string GetMd5Hash(string input)
        {
            using (MD5 md5 = MD5.Create())
            {
                byte[] inputBytes = Encoding.ASCII.GetBytes(input);
                byte[] hashBytes = md5.ComputeHash(inputBytes);

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < hashBytes.Length; i++)
                {
                    sb.Append(hashBytes[i].ToString("X2"));
                }
                return sb.ToString();
            }
        }

        private List<DownloadM3u8TaskItem> GetTaskItem(
            string lastPlayerUrl,
            string videoName,
            EncryptMethod method,
            string key,
            string IV
        )
        {
            if (string.IsNullOrEmpty(videoName))
            {
                videoName = GetMd5Hash(lastPlayerUrl);
            }
            if (lastPlayerUrl.Contains(".m3u8"))
            {
                DownloadM3u8TaskItem item = new DownloadM3u8TaskItem()
                {
                    RequestUrl = new Uri(lastPlayerUrl),
                    VideoName = videoName,
                    Method = method,
                    Key = key,
                    Iv = IV,
                };
                List<DownloadM3u8TaskItem> tasks = new List<DownloadM3u8TaskItem>();
                tasks.Add(item);
                return tasks;
            }
            else
            {
                return ParseHtml(lastPlayerUrl, videoName, method, key, IV);
            }
        }

        private List<DownloadM3u8TaskItem> ParseHtml(
            string lastPlayerUrl,
            string videoName,
            EncryptMethod method,
            string key,
            string IV
        )
        {
            if (lastPlayerUrl == null)
                return null;
            if (lastPlayerUrl.Contains("chrqj.com"))
            {
                return ParseChrqj(lastPlayerUrl, videoName, method, key, IV);
            }
            else
            {
                return parseOtherHTML(lastPlayerUrl, videoName, method, key, IV);
            }
        }

        private List<DownloadM3u8TaskItem> parseOtherHTML(
            string lastPlayerUrl,
            string videoName,
            EncryptMethod method,
            string key,
            string IV
        )
        {
            List<DownloadM3u8TaskItem> tasks = new List<DownloadM3u8TaskItem>();

            Dictionary<int, string> urls = new Dictionary<int, string>();
            M3u8 m3u8 = null;
            foreach (string k in m3u8Dict.Keys)
            {
                if (lastPlayerUrl.Contains(k))
                {
                    m3u8 = m3u8Dict[k];
                }
            }
            if (m3u8 == null)
            {
                System.Windows.Forms.MessageBox.Show(
                    "没有该网站的配置文件\n请修改m3u8.json",
                    "无相关配置"
                );
                return tasks;
            }
            Match urlMatch = Regex.Match(lastPlayerUrl, m3u8.urlReg);
            int count = 0;
            string prefix = "";
            string endWith = "";
            if (urlMatch.Success)
            {
                count = int.Parse(urlMatch.Groups[2].Value);
                prefix = urlMatch.Groups[1].Value;
                endWith = urlMatch.Groups[3].Value;
            }
            Regex re = new Regex(m3u8.urlReg, RegexOptions.Singleline);
            string xurl = prefix + "{0}" + endWith;
            HttpClient client = new HttpClient();
            //System.Net.Http.Headers.HttpRequestHeaders defaultRequestHeaders = client.DefaultRequestHeaders;
            //defaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3");
            //defaultRequestHeaders.Accept.ParseAdd("text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7");
            //defaultRequestHeaders.AcceptLanguage.ParseAdd("zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6");
            //defaultRequestHeaders.AcceptEncoding.ParseAdd("gzip, deflate, br, zstd");
            //defaultRequestHeaders.Connection.ParseAdd("keep-alive");
            string title = "";
            for (int i = m3u8.start; i <= count; i++)
            {
                string url = string.Format(xurl, i);

                //Log.Information(url);
                string source = client.GetStringAsync(url).GetAwaiter().GetResult();
                //Log.Information(source);
                Match titleMatch = Regex.Match(source, m3u8.titleReg);
                if (titleMatch.Success)
                {
                    title = titleMatch.Groups[1].Value;
                }
                Match m3u8UrlMatch = Regex.Match(source, m3u8.m3u8UrlReg);
                string m3u8Url = "";
                if (m3u8UrlMatch.Success)
                {
                    m3u8Url = m3u8UrlMatch.Groups[1].Value;
                    m3u8Url = m3u8Url.Replace("\\", "");
                    m3u8Url = m3u8Url.Replace("%3A", ":");
                    m3u8Url = m3u8Url.Replace("%2F", "/");
                    if (urls.ContainsKey(m3u8.start == 1 ? i : i + 1))
                    {
                        urls.Remove(m3u8.start == 1 ? i : i + 1);
                    }
                    urls.Add(m3u8.start == 1 ? i : i + 1, m3u8Url);
                }
                Thread.Sleep(10);
            }

            if (urls.Count > 0)
            {
                urls.SortedKeys();
                foreach (KeyValuePair<int, string> pair in urls)
                {
                    DownloadM3u8TaskItem taskItem = new DownloadM3u8TaskItem()
                    {
                        RequestUrl = new Uri(pair.Value),
                        VideoName =
                            urls.Count == 1
                                ? title
                                : title + "/" + (pair.Key < 10 ? "0" : "") + pair.Key.ToString(),
                        Method = method,
                        Key = key,
                        Iv = IV,
                    };
                    tasks.Add(taskItem);
                }
            }
            tasks.Sort((o1, o2) => o1.VideoName.CompareTo(o2.VideoName));
            return tasks;
        }

        private List<DownloadM3u8TaskItem> ParseChrqj(
            string lastPlayerUrl,
            string videoName,
            EncryptMethod method,
            string key,
            string IV
        )
        {
            List<DownloadM3u8TaskItem> tasks = new List<DownloadM3u8TaskItem>();
            string pythonScriptPath =
                "chrqj.com.py " + lastPlayerUrl + " " + AppConfig.Instance.SavePath;
            string PythonExePath = @"python.exe"; //Python 解释器路径
            ProcessStartInfo startInfo = new ProcessStartInfo(PythonExePath, pythonScriptPath)
            {
                RedirectStandardOutput = true,
                UseShellExecute = false,
                CreateNoWindow = true,
            };
            using (Process process = new Process())
            {
                process.StartInfo = startInfo;
                process.Start();
                //读取 Python 脚本的输出
                string output = process.StandardOutput.ReadToEnd();
                process.WaitForExit();
                List<Dictionary<string, string>> list = JsonConvert.DeserializeObject<
                    List<Dictionary<string, string>>
                >(output);
                list.Sort((o1, o2) => o1["name"].CompareTo(o2["name"]));
                foreach (var di in list)
                {
                    tasks.Add(
                        new DownloadM3u8TaskItem()
                        {
                            RequestUrl = new Uri(di["url"]),
                            VideoName = di["name"],
                            Method = method,
                            Key = key,
                            Iv = IV,
                        }
                    );
                }
            }
            return tasks;
        }
    }
}
